import java.util.ArrayList;
import java.util.Collection;

public class Task implements Comparable<Task>
{
	private Collection<Task> predecessors;
	
	private Collection<Task> successors;
	
	private String taskId;
	
	private Integer duration;	
	
	private Integer earlyStart;

	private Integer lateStart;	
	
	private Integer earlyFinish;
	
	private Integer lateFinish;
	
	private Integer slack;
	
	private boolean isCritical;
	
	public Task( String taskId, Integer duration ) {
		this.taskId = taskId;
		this.duration = duration;
		predecessors = new ArrayList<Task>();
		successors = new ArrayList<Task>();
	}
	
	public Collection<Task> getPredecessors( )
	{
		return predecessors;
	}
	
	public Collection<Task> getSuccessors( )
	{
		return successors;
	}
	
	public void addPredecessor( Task task )
	{
		predecessors.add(task);
	}
	
	public void addSuccessor( Task task ) {
		successors.add(task);
	}
	
	
	public Integer getDuration( )
	{
		return duration;
	}
	
	
	public String getTaskId( )
	{
		return taskId;
	}
	
	public Integer getEarlyStart( ) {
		return earlyStart;
	}

	public void setEarlyStart( Integer earlyStart ) {
		this.earlyStart = earlyStart;
	}

	public Integer getLateStart( ) {
		return lateStart;
	}

	public void setLateStart( Integer lateStart ) {
		this.lateStart = lateStart;
	}

	public Integer getEarlyFinish( ) {
		return earlyFinish;
	}

	public void setEarlyFinish( Integer earlyFinish ) {
		this.earlyFinish = earlyFinish;
	}

	public Integer getLateFinish( ) {
		return lateFinish;
	}

	public void setLateFinish( Integer lateFinish ) {
		this.lateFinish = lateFinish;
	}

	public Integer getSlack( ) {
		return slack;
	}

	public void setSlack( Integer slack ) {
		this.slack = slack;
	}

	public boolean getIsCritical( ) {
		return isCritical;
	}

	public void setIsCritical( boolean isCritical ) {
		this.isCritical = isCritical;
	}

	public Integer calculateEarlyStart( ) {
		if(predecessors.size() == 0) {
			earlyStart = 0;
			return earlyStart;
		} else {
			Integer latestFinish = 0;
			
			for(Task preceedingTask : predecessors) {
				if(preceedingTask.getEarlyFinish() == null) {
					preceedingTask.calculateEarlyTimes();
				}
				if(preceedingTask.getEarlyFinish() > latestFinish) {
					latestFinish = preceedingTask.getEarlyFinish();
				}
			}
			
			earlyStart = latestFinish;
			return earlyStart;	
		}
	}
	
	public Integer calculateLateStart( ) {
		lateStart = lateFinish - duration;
		return lateStart;
	}
	
	public Integer calculateEarlyFinish( ) {
		earlyFinish = earlyStart + duration;
		return earlyFinish;
	}
	
	public Integer calculateLateFinish( ) {
		if(successors.size() == 0) {
			lateFinish = earlyFinish;
			return lateFinish;
		} else {
			Integer earliestStart = Integer.MAX_VALUE;
				
			for(Task succeedingTask : successors) {
				if(succeedingTask.getLateStart() == null) {
					succeedingTask.calculateLateTimes();
				}
				if(succeedingTask.getLateStart() < earliestStart) {
					earliestStart = succeedingTask.getLateStart();
				}
			}
			
			lateFinish = earliestStart;
			return lateFinish;	
		}
	}
	
	public Integer calculateSlack( ) {
		slack = lateStart - earlyStart;
		
		if(slack == 0) {
			isCritical = true;
		}
		
		return slack;
	}

	@Override
	public int compareTo( Task task ) {
		return this.taskId.compareTo( task.getTaskId());
	}

	public void calculateEarlyTimes( ) {
		calculateEarlyStart();
		calculateEarlyFinish();	
	}
	
	public void calculateLateTimes( ) {
		calculateLateFinish();
		calculateLateStart();
	}

	@Override
	public String toString( ) {
		return "ID: " + getTaskId() + ", early start: " + getEarlyStart() + 
				", Early finish: " + getEarlyFinish() + ", Late start: " + getLateStart() +
				", Late finish: " + getLateFinish() + ", Slack: " + getSlack();
	}
	
}
